# Generate C code for standard int and float operators.

bool_ops = [ 'and_', 'or_', 'xor' ]
int_ops = [ 'and_', 'or_', 'xor', 'rshift', 'mod' ]
c_ops = [ 'add', 'sub', 'mul' ]
compare_ops = [ ('eq', '=='), ('ne', '!='), ('lt', '<'),  ('gt', '>'),  ('le', '<='),  ('ge', '>=')  ]
syms = { 'and_' : '&' , 'or_' : '|' , 'xor' : '^', 'lshift' : '<<', 'rshift' : '>>', 'add' : '+', 
        'sub' : '-', 'mul' : '*', 'truediv' : '/', 'floordiv' : '//', 'mod' : '%', 'pow' : '**', 
        'neg' : '-', 'pos' : '+', 'invert' : '!' }
uns = [ 'neg', 'pos' ]

def integer(op, sym, overflow):
    print "extern R_object PY_FUNC2(%s_int_int, R_int i0, R_int i1); " % op

def compare(op, sym, left, right):
    print """R_object PY_FUNC2(%s_%s_%s, R_%s p0, R_%s p1) {
    int cmp;
    intptr_t i0, i1;
    double d0, d1;
    GVMT_NO_GC_BLOCK_BEGIN 
    TYPE_ASSERT(p0, %s);
    TYPE_ASSERT(p1, %s);""" % (op, left, right, left, right, left, right)
    if left == 'int':
        if right == 'int':
            print """    i0 = (intptr_t)gvmt___untag__((GVMT_Object)p0);
    i1 = (intptr_t)gvmt___untag__((GVMT_Object)p1);
    if (i0 & i1 & 1)
        return (R_object)booleans[i0 %s i1];
    else                       
        cmp = py_int_int_compare(p0, p1);""" % sym
        else:
            print "    d1 = p1->value;"
            print "    if (d1 != d1) return (R_object)FALSE;"
            print "    cmp = py_int_double_compare(p0, d1);"
    else:
        if right == 'int':
            print "    d0 = p0->value;"
            print "    if (d0 != d0) return (R_object)FALSE;"
            print "    cmp = -py_int_double_compare(p1, d0);"
        else:
            print "    d0 = p0->value;"
            print "    d1 = p1->value;"
            print "    if (d0 != d0 || d1 != d1) return (R_object)FALSE;"
            print "    GVMT_NO_GC_BLOCK_END"
            print "    return (R_object)booleans[d0 %s d1];" % sym
            print "}"
            print
            return
    print "    GVMT_NO_GC_BLOCK_END"
    print "    return (R_object)booleans[cmp %s 0]; " % sym
    print "}"
    print
    
def str_comp(op, sym):
    print """R_object PY_FUNC2(%s_str_str, R_str p0, R_str p1) {
    TYPE_ASSERT(p0, str);
    TYPE_ASSERT(p1, str);
    return (R_object)booleans[string_compare(p0, p1) %s 0];
}
""" % (op, sym)
  
def floating(op, sym, left, right):
    print """R_object PY_FUNC2(%s_%s_%s, R_%s p0, R_%s p1) {
    R_float result;
    double value;
    TYPE_ASSERT(p0, %s);
    TYPE_ASSERT(p1, %s);""" % (op, left, right, left, right, left, right)
    tname = 'float'
    if left == 'int':
        lhs = 'double_from_py_int(p0)'
    else:
        assert left == 'float'
        lhs  = 'p0->value'
    if right == 'int':
        rhs = 'double_from_py_int(p1)'
    else:
        assert right == 'float'
        rhs  = 'p1->value'
    if left == 'int' and  right == 'int':
        tname = 'integer'
    if sym  == '/':
        print '    value = %s;' % rhs
        print '    if (value == 0.0) zero_division_error("%s division");' % tname
        rhs = 'value'
    if sym  == '%':
        print '    value = %s;' % rhs
        print '    if (value == 0.0) zero_division_error("%s modulo");'  % tname
        rhs = 'value'
    print '    value = %s %s %s;' % (lhs, sym, rhs)
    print '    result = gc_allocate(float);'
    print '    SET_TYPE(result, type_float);'
    print "    result->value = value;"
    print "    return (R_object)result;"
    print "}\n"
    
     
def iop(op):
    if op[-1] == '_':
        return 'i' + op[:-1]
    else:
         return 'i' + op   
    
def delegate(op, left, right):
    print """PY_FUNC2(%s_%s_%s, R_%s p0, R_%s p1) {
    return PY_%s_%s_%s(function, p1, p0);
}\n""" % (iop(op), left, right, left, right, op, left, right)

def comp(left, right):
    print """R_object PY_FUNC2(cmp_%s_%s, R_%s p0, R_%s p1) {
    TYPE_ASSERT(p0, %s);
    TYPE_ASSERT(p1, %s);
    if (p0->value == p1->value) {
        return (R_object)PY_SMALL_INT(0);
    } else {
        if (p0->value < p1->value) {
            return (R_object)PY_SMALL_INT(-1);
        } else {
            return (R_object)PY_SMALL_INT(1);
        }
    }
}
""" % (left, right, left, right, left, right)

#    
#def integer(op, sym, overflow):
#    integer(op, sym, overflow)
#    delegate(op, 'int', 'int')
#    
#def floating(op, sym, left, right):
#    floating(op, sym, left, right)
#    delegate(op, left, right)
    
import sys    
print '/* This file is automatically generated */'

f = open(sys.argv[1])
for line in f:
    print line,
for op in c_ops:
    integer(op, syms[op], True)
    floating(op, syms[op], 'int', 'float') 
    floating(op, syms[op], 'float', 'int') 
    floating(op, syms[op], 'float', 'float')
for op in int_ops:
    integer(op, syms[op], False)
integer('lshift', '<<', True)
integer('floordiv', '/', True)
integer('truediv', '/', True)
floating('truediv', '/', 'int', 'int') 
floating('truediv', '/', 'int', 'float') 
floating('truediv', '/', 'float', 'int') 
floating('truediv', '/', 'float', 'float')
for p in compare_ops:
    compare(p[0], p[1], 'int', 'int')
    compare(p[0], p[1], 'int', 'float') 
    compare(p[0], p[1], 'float', 'int') 
    compare(p[0], p[1], 'float', 'float')
str_comp('lt', '<') 
str_comp('gt', '>')
str_comp('le', '<=')
str_comp('ge', '>=')
#for op in bool_ops:
#    delegate(op, 'bool', 'bool')
#delegate('pow', 'int', 'int')
#delegate('pow', 'int', 'float')
#delegate('pow', 'float', 'int')
#delegate('pow', 'float', 'float')
#comp('int', 'int')
#comp('int', 'float')
#comp('float', 'int')
comp('float', 'float')

